﻿#pragma once
#define GLFW_INCLUDE_VULKAN
#include "GLFW/glfw3.h"
#include <array>
#include <vector>
#include <optional>
#include "glm/glm.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/hash.hpp"

struct QueueFamilyIndices
{
	std::optional<uint32_t> graphicsFamily;	// 绘图队列族
	std::optional<uint32_t> presentFamily;	// 演示队列族

	bool IsComplete()
	{
		return graphicsFamily.has_value() && presentFamily.has_value();
	}
};

struct SwapChainSupportDetails
{
	VkSurfaceCapabilitiesKHR capabilities;		// 基本表面功能（交换链中的图像最小/最大数量，图像的最小/最大宽度和高度）
	std::vector<VkSurfaceFormatKHR> formats;	// 表面格式（像素格式，颜色空间）
	std::vector<VkPresentModeKHR> presentModes;	// 演示模式
};

struct Vertex
{
	glm::vec3 pos;
	glm::vec3 color;
	glm::vec2 texCoord;

	static VkVertexInputBindingDescription GetBindingDescription();
	static std::array<VkVertexInputAttributeDescription, 3> GetAttributeDescriptions();

	bool operator==(const Vertex& other) const
	{
		return pos == other.pos && color == other.color && texCoord == other.texCoord;
	}
};

namespace std {
	template<> struct hash<Vertex> 
	{
		size_t operator()(Vertex const& vertex) const 
		{
			return ((hash<glm::vec3>()(vertex.pos) ^
				(hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
				(hash<glm::vec2>()(vertex.texCoord) << 1);
		}
	};
}

struct UniformBufferObject
{
	alignas(16) glm::mat4 model;
	alignas(16) glm::mat4 view;
	alignas(16) glm::mat4 proj;
};

const size_t MAX_FRAMES_IN_FLIGHT = 2;	//同时处理的帧数

class MainApplication
{
public:
	void Run();
private:
	void InitWindow();
	void InitVulkan();
	void MainLoop();
	void CleanUp();

private:
	// 窗口缩放回调
	static void frameBufferResizeCallback(GLFWwindow* window, int width, int height);

// 准备工作
private:
	// 生成vulkan实例
	void CreateInstance();
	// 设置调试消息管理器
	void SetupDebugMessenger();
	// 创建窗口表面
	void CreateSurface();
	// 获取一个支持app的物理设备
	void PickPhysicalDevice();
	// 创建逻辑设备
	void CreateLogicalDevice();
	// 创建交换链
	void CreateSwapChain();
	// 创建图像视图
	void CreateImageViews();
	// 创建渲染过程
	void CreateRenderPass();
	// 创建描述符布局（定义uniform）
	void CreateDescriptorSetLayout();
	// 创建渲染管线
	void CreateGraphicsPipeline();
	// 创建帧缓冲
	void CreateFrameBuffers();
	// 创建命令池
	void CreateCommandPool();
	// 创建多重缓冲资源
	void CreateColorResources();
	// 创建深度资源
	void CreateDepthResources();
	// 创建纹理
	void CreateTextureImage();
	// 创建图像视图
	void CreateTextureImageView();
	// 创建图像采样器
	void CreateTextureSampler();
	// 导入模型
	void LoadModel();
	// 创建顶点缓冲区
	void CreateVertexBuffer();
	// 创建索引缓冲区
	void CreateIndexBuffer();
	// 创建Uniform变量缓冲区
	void CreateUniformBuffers();
	// 创建描述符池
	void CreateDescriptorPool();
	// 创建描述符集
	void CreateDescriptorSets();
	// 分配命令缓冲区
	void CreateCommandBuffers();
	// 创建信号量
	void CreateSyncObjects();
// 主循环
private:
	void DrawFrame();
	// 交换链重建
	void RecreateSwapChain();
	// 清除交换链
	void CleanUpSwapChain();
	// 更新Uniform变量
	void UpdateUniformBuffer(uint32_t currentImage);
private:
	// 检查验证层是否支持
	bool CheckValidationLayerSupport();
	std::vector<const char*> GetRequiredExtensions();

	// 准备验证层消息管理器的创建数据
	void PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
	// 创建验证层的消息管理器
	VkResult CreateDebugUtilsMessengerEXT(
		VkInstance instance, 
		const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, 
		const VkAllocationCallbacks* pAllocator, 
		VkDebugUtilsMessengerEXT* pDebugMessenger);
	// 销毁验证层的消息管理器
	void DestroyDebugUtilsMessengerEXT(
		VkInstance instance,
		VkDebugUtilsMessengerEXT debugMessenger,
		const VkAllocationCallbacks* pAllocator);

	// 检查设备是否可用
	bool IsDeviceSuitable(VkPhysicalDevice physicalDevice);
	// 查找设备支持的命令队列
	QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice physicalDevice);
	// 检查设备支持的扩展
	bool CheckDeviceExtensionSupport(VkPhysicalDevice physicalDevice);
	// 查询交换链支持的详细信息
	SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice physicalDevice);

	// 获取交换链的最佳表面格式（颜色深度）
	VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
	// 获取交换链的最佳呈现模式（图像交换到屏幕的条件）
	VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
	// 获取交换链的最佳交换范围（交换链中的图像分辨率）
	VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);

	// 创建着色器模块
	VkShaderModule CreateShaderModule(const std::vector<char>& code);

	// 查询内存类型
	uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;

	// 抽象缓冲创建函数
	void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
	// 抽象创建图像函数
	void CreateImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
	// 创建mipmap图像
	void GenerateMipmaps(VkImage image, VkFormat imageFormat,int32_t texWidth, int32_t texHeight, uint32_t mipLevels);

	// 开始一次命令
	VkCommandBuffer BeginSingleTimeCommands();
	// 结束一次命令
	void EndSingleTimeCommands(VkCommandBuffer commandBuffer);

	// 拷贝缓冲区(CPU->GPU)
	void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
	// 图像布局转换
	void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels);
	// 拷贝缓冲区到图像
	void CopyBufferToImage(VkBuffer srcBuffer, VkImage image, uint32_t width, uint32_t height);

	VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectMask, uint32_t mipLevels);

	// 查找最佳的受支持的格式
	VkFormat FindSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);

	// 查找深度缓冲的最佳的格式
	VkFormat FindDepthFormat();

	// 获取支持的多重采样数
	VkSampleCountFlagBits GetMaxUsableSampleCount();

	// 记录命令缓冲区
	void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex);
private:
	GLFWwindow* m_window{ nullptr };

	VkInstance m_instance{ nullptr }; 
	VkDebugUtilsMessengerEXT m_debugMessenger{ nullptr };
	VkSurfaceKHR m_surface{ nullptr };	// 渲染目标（可选，离屏渲染就不需要）
	
	VkPhysicalDevice m_physicalDevice{ nullptr };// instance销毁时这个自动销毁
	VkDevice m_device{ nullptr };

	VkSwapchainKHR m_swapChain{ nullptr };
	std::vector<VkImage> m_swapChainImages;	// 清理交换链时自动清理
	VkFormat m_swapChainImageFormat;
	VkExtent2D m_swapChainExtent;
	std::vector<VkImageView> m_swapChainImageViews;

	QueueFamilyIndices m_queueIndices;
	VkQueue m_graphicsQueue{ nullptr };	// 逻辑设备创建时自动创建，逻辑设备销毁时自动销毁
	VkQueue m_presentQueue{ nullptr };

	bool m_enableValidationLayers{ false };
	const std::vector<char const*> m_validation_layers{ "VK_LAYER_KHRONOS_validation" };
	std::vector<char const*> m_deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

	VkRenderPass m_renderPass{ nullptr };
	VkDescriptorSetLayout m_descriptorSetLayout{ nullptr };
	VkPipelineLayout m_pipelineLayout{ nullptr };
	VkPipeline m_graphicsPipeline{ nullptr };

	std::vector<VkFramebuffer> m_swapChainFrameBuffers;
	VkCommandPool m_commandPool{ nullptr };
	std::vector<VkCommandBuffer> m_commandBuffers;

	// 同步量
	std::vector<VkSemaphore> m_imageAvailableSemaphores;
	std::vector<VkSemaphore> m_renderFinishedSemaphores;
	std::vector<VkFence> m_inFlightFences;
	bool m_frameBufferResized = false;

	size_t m_currentFrame = 0;

	VkBuffer m_vertexBuffer{ nullptr };
	VkDeviceMemory m_vertexBufferMemory{ nullptr };
	VkBuffer m_indexBuffer{ nullptr };
	VkDeviceMemory m_indexBufferMemory{ nullptr };
	std::vector<VkBuffer> m_uniformBuffers;
	std::vector<VkDeviceMemory> m_uniformBuffersMemory;
	std::vector<void*> m_uniformBuffersMapped;
	VkDescriptorPool m_descriptorPool{ nullptr };
	std::vector<VkDescriptorSet> m_descriptorSets;

	uint32_t m_mipLevels = 1;
	VkImage m_textureImage{ nullptr };
	VkDeviceMemory m_textureImageMemory{ nullptr };
	VkImageView m_textureImageView{ nullptr };
	VkSampler m_textureSampler{ nullptr };

	VkImage m_depthImage;
	VkDeviceMemory m_depthImageMemory;
	VkImageView m_depthImageView;

	// 模型
	std::vector<Vertex> m_vertices;
	std::vector<uint32_t> m_indices;

	// 多重采样
	VkSampleCountFlagBits m_msaaSamples = VK_SAMPLE_COUNT_1_BIT;
	VkImage m_colorImage;
	VkDeviceMemory m_colorImageMemory;
	VkImageView m_colorImageView;
};
